package com.kinglumi.ailighting.auth.login.account;

import com.kinglumi.ailighting.auth.constant.ServiceErrorEnum;
import com.kinglumi.ailighting.auth.exception.BaseBusinessException;
import com.kinglumi.ailighting.auth.service.auth.impl.CustomUserDetailsService;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * @author Lxin
 * @version 1.0
 * @date 2021/8/13 14:31
 */
public class AccountAuthenticationProvider implements AuthenticationProvider {
    private CustomUserDetailsService userDetailsService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        UsernamePasswordAuthenticationToken authenticationToken = (UsernamePasswordAuthenticationToken) authentication;
        //获取手机号码和验证码
        String username = determineUsername(authentication);
        String password = (String) authenticationToken.getCredentials();
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        checkPassword(password, userDetails.getPassword());
        return createSuccessAuthentication(userDetails, authentication, userDetails);
    }

    private void checkPassword(String password, String userDetails) {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        boolean matches = bCryptPasswordEncoder.matches(password, userDetails);
        if (!matches) {
            throw new BaseBusinessException(ServiceErrorEnum.PASSWORD_ERROR);
        }
    }

    private String determineUsername(Authentication authentication) {
        return (authentication.getPrincipal() == null) ? "NONE_PROVIDED" : authentication.getName();
    }

    private UsernamePasswordAuthenticationToken createSuccessAuthentication(Object principal, Authentication authentication,
                                                                            UserDetails user) {
        // Ensure we return the original credentials the user supplied,
        // so subsequent attempts are successful even with encoded passwords.
        // Also ensure we return the original getDetails(), so that future
        // authentication events after cache expiry contain the details
        UsernamePasswordAuthenticationToken authenticationResult =
                new UsernamePasswordAuthenticationToken(principal, authentication.getCredentials(), user.getAuthorities());
        authenticationResult.setDetails(authentication.getDetails());
        return authenticationResult;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        // 判断 authentication 是不是 SmsCodeAuthenticationToken 的子类
        return UsernamePasswordAuthenticationToken.class.isAssignableFrom(aClass);
    }

    public CustomUserDetailsService getUserDetailsService() {
        return userDetailsService;
    }

    public void setUserDetailsService(CustomUserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }
}
